package maestro;

import java.math.BigDecimal;
import java.math.MathContext;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
/**
 *
 * @author sala_a
 */
public class Maestro extends UnicastRemoteObject implements interfaz_maaestro.InterfaceRemote {

    private HashMap<String, Boolean> maquinasClientes;
    private HiloEscuchandoDireccionesPC direccionesEscuchadas_PC;
    private HiloEnviandoBroadcast broadcast;
   
    public Maestro() throws RemoteException {
        maquinasClientes = new HashMap<>();
        direccionesEscuchadas_PC = new HiloEscuchandoDireccionesPC(maquinasClientes);
        broadcast = new HiloEnviandoBroadcast(maquinasClientes);
        new Thread(direccionesEscuchadas_PC).start();
        new Thread(broadcast).start();
    }

    
    public String informarSO(String IP) throws Exception {
        
        maquinasClientes = direccionesEscuchadas_PC.getDirecciones();
        boolean bandera = false;
        String data = "";
        System.out.println("entro al try: "+maquinasClientes.size());
        for (String s : maquinasClientes.keySet()) {
            
            if (maquinasClientes.get(s) == true) {
                Registry reg;
                try {
                    if (s.equals(IP)) {
                        reg = LocateRegistry.getRegistry(s, 1099);
                        interfaz_esclavo.InterfaceRemote interfaces = (interfaz_esclavo.InterfaceRemote) reg.lookup("esclavo");
                        data = (interfaces.informarSO());
                        bandera = true;
                    }

                } catch (Exception ex) {
                    Logger.getLogger(Maestro.class.getName()).log(Level.SEVERE, null, ex);
                }

            }

        }
        if (bandera == false) {
            data = "El esclavo no está disponible";
        }
        return data;
    }

    public String informarCpu(String IP) throws Exception {
         maquinasClientes = direccionesEscuchadas_PC.getDirecciones();
        boolean bandera = false;
        String data = "";
        for (String s : maquinasClientes.keySet()) {
            if (maquinasClientes.get(s) == true) {
                Registry reg;
                try {
                    if (s.equals(IP)) {
                        reg = LocateRegistry.getRegistry(s, 1099);
                        interfaz_esclavo.InterfaceRemote interfaces = (interfaz_esclavo.InterfaceRemote) reg.lookup("esclavo");
                        data = (interfaces.informarCpu());
                        bandera = true;
                    }

                } catch (Exception ex) {
                    Logger.getLogger(Maestro.class.getName()).log(Level.SEVERE, null, ex);
                }

            }

        }
        if (bandera == false) {
            data = "El esclavo no está disponible";
        }
        return data;
    }

    @Override
    public String infoDiscoArchivos(String IP) throws Exception {
         maquinasClientes = direccionesEscuchadas_PC.getDirecciones();
        boolean bandera = false;
        String data = "";
        for (String s : maquinasClientes.keySet()) {
            if (maquinasClientes.get(s) == true) {
                Registry reg;
                try {
                    if (s.equals(IP)) {
                        reg = LocateRegistry.getRegistry(s, 1099);
                        interfaz_esclavo.InterfaceRemote interfaces = (interfaz_esclavo.InterfaceRemote) reg.lookup("esclavo");
                        data = (interfaces.infoDiscoArchivos());
                        bandera = true;
                    }

                } catch (Exception ex) {
                    Logger.getLogger(Maestro.class.getName()).log(Level.SEVERE, null, ex);
                }

            }

        }
        if (bandera == false) {
            data = "El esclavo no está disponible";
        }
        return data;
    }

    @Override
    public String infoMemoria(String IP) throws Exception {
         maquinasClientes = direccionesEscuchadas_PC.getDirecciones();
        boolean bandera = false;
        String data = "";
        for (String s : maquinasClientes.keySet()) {
            if (maquinasClientes.get(s) == true) {
                Registry reg;
                try {
                    if (s.equals(IP)) {
                        reg = LocateRegistry.getRegistry(s, 1099);
                        interfaz_esclavo.InterfaceRemote interfaces = (interfaz_esclavo.InterfaceRemote) reg.lookup("esclavo");
                        data = (interfaces.infoMemoria());
                        bandera = true;
                    }

                } catch (Exception ex) {
                    Logger.getLogger(Maestro.class.getName()).log(Level.SEVERE, null, ex);
                }

            }

        }
        if (bandera == false) {
            data = "El esclavo no está disponible";
        }
        return data;
    }

    @Override
    public String infoHilosProcesos(String IP) throws Exception {
         maquinasClientes = direccionesEscuchadas_PC.getDirecciones();
        boolean bandera = false;
        String data = "";
        
        for (String s : maquinasClientes.keySet()) {
            
            if (maquinasClientes.get(s) == true) {
                Registry reg;
                try {
                    
                    if (s.equals(IP)) {
                        System.out.println(s+"="+IP);
                        reg = LocateRegistry.getRegistry(s, 1099);
                        interfaz_esclavo.InterfaceRemote interfaces = (interfaz_esclavo.InterfaceRemote) reg.lookup("esclavo");
                        data = (interfaces.infoHilosProcesos());
                        bandera = true;
                    }

                } catch (Exception ex) {
                    Logger.getLogger(Maestro.class.getName()).log(Level.SEVERE, null, ex);
                }

            }

        }
        if (bandera == false) {
            data = "El esclavo no está disponible";
        }
        return data;
    }

    @Override
    public String infoEstaticaCpu(String IP) throws Exception {
         maquinasClientes = direccionesEscuchadas_PC.getDirecciones();
        boolean bandera = false;
        String data = "";
        for (String s : maquinasClientes.keySet()) {
            if (maquinasClientes.get(s) == true) {
                Registry reg;
                try {
                    if (s.equals(IP)) {
                        reg = LocateRegistry.getRegistry(s, 1099);
                        interfaz_esclavo.InterfaceRemote interfaces = (interfaz_esclavo.InterfaceRemote) reg.lookup("esclavo");
                        data = (interfaces.infoEstaticaCpu());
                        bandera = true;
                    }

                } catch (Exception ex) {
                    Logger.getLogger(Maestro.class.getName()).log(Level.SEVERE, null, ex);
                }

            }

        }
        if (bandera == false) {
            data = "El esclavo no está disponible";
        }
        return data;
    }
    
    public Map retornarMapa () throws Exception
    {
        maquinasClientes = direccionesEscuchadas_PC.getDirecciones();
        System.out.println("maquinas size: "+maquinasClientes.toString());
        return maquinasClientes;
    }
    
     public String buscarDireccionDisponible(){
        try {
            return balancearCargas();
            
        } catch (Exception ex) {
            System.out.println("Error en buscar dirección disponible: "+ex);
        }
        return null;
    }
     
     public String balancearCargas() throws RemoteException, NotBoundException{
        int min = -1;
        String direccion=null;
        for (String s : maquinasClientes.keySet()){
            if (maquinasClientes.get(s)==true){
                try{
                    Registry reg = LocateRegistry.getRegistry(s,1099);
                    interfaz_esclavo.InterfaceRemote  interfaz;
                    interfaz = (interfaz_esclavo.InterfaceRemote)reg.lookup("PC");
                    int cantidad = interfaz.informarCpu().length();
                    System.out.println("CantProc "+s+" "+Integer.toString(cantidad));
                    if (min == -1){
                        direccion = s;
                        min = cantidad;
                    }else{
                        if (cantidad<min){
                            min = cantidad;
                            direccion = s;
                        }
                    }
                }catch(Exception e){
                    System.out.println("Se murio este care chimba" +s);
                }
             }
        }
        return direccion;
     }
     
      public BigDecimal Euler (double n)
    {
        BigDecimal resultado;
        
        resultado =  BigDecimal.valueOf((Math.pow(n, 2))+n+41);
        return resultado;
    }
    
    public BigDecimal Legender (double n)
    {
        BigDecimal resultado;
        resultado = BigDecimal.valueOf(2*(Math.pow(n, 2))+39); 
        return resultado;        
    }
    
    public BigDecimal Brox (double n)
    {
        BigDecimal resultado;
        resultado = BigDecimal.valueOf(6*(Math.pow(n, 2))-342*n+4903);
        return resultado;
    }
    
    public static BigDecimal calcularPi (int n)
    {
         MathContext mc = new MathContext(n);
        BigDecimal pi = new BigDecimal(0);
        BigDecimal limit = new BigDecimal(1).movePointLeft(n);
        boolean stop = false;
        for (int k = 0; !stop; k++) {
            BigDecimal piK = piFunction(k, mc);
            pi = pi.add(piK);
            if (piK.compareTo(limit) < 0) {
                stop = true;
            }
        }
        return pi.round(mc);
    }
    
    private static BigDecimal piFunction(int k, MathContext mc) {
        int k8 = 8 * k;
        
        BigDecimal val1 = new BigDecimal(4);
        val1 = val1.divide(new BigDecimal(k8 + 1), mc);
        BigDecimal val2 = new BigDecimal(-2);
        val2 = val2.divide(new BigDecimal(k8 + 4), mc);
        BigDecimal val3 = new BigDecimal(-1);
        val3 = val3.divide(new BigDecimal(k8 + 5), mc);
        BigDecimal val4 = new BigDecimal(-1);
        val4 = val4.divide(new BigDecimal(k8 + 6), mc);
        BigDecimal val = val1;
        val = val.add(val2);
        val = val.add(val3);
        val = val.add(val4);
        BigDecimal multiplier = new BigDecimal(16);
        multiplier = multiplier.pow(k);
        BigDecimal one = new BigDecimal(1);
        multiplier = one.divide(multiplier, mc);
        val = val.multiply(multiplier);
        return val;
        
        
    }
    
}
